package jcommand;

import java.io.IOException;
import java.util.Vector;

/**
 * A set of actions which assigned with a command key. The idea of command key
 * is the same as the primary key of a database. The developer can use this key
 * to identify the command in {@link jcommand.CommandSet}<br>
 * <br>
 * The <code>commandKey</code> is <code>final</code>, so once the command
 * is created, it cannot be modified.<br>
 * <br>
 * Example: Create a command which included a set of actions <code>
 * <br>Command c1 = new Command("SayHelloToGrace");
 * <br>c1.addAction(Action.TypeWord("Hello"));
 * <br>c1.addAction(Action.KeyPress("KeyEvent.ENTER"));
 * <br>c1.addAction(Action.TypeWord("Grace"));
 * <br>c1.runCommand();
 * </code>
 * 
 * @author Kenneth Lo
 * @see jcommand.Action
 * @see jcommand.CommandSet
 * @since 1.0.0
 */
public class Command {

	/**
	 * The unique identify key of the command.
	 * 
	 * @since 1.0.0
	 */
	private final String commandKey;

	/**
	 * A Vector with type {@link jcommand.Action} that store all the actions.
	 * 
	 * @since 1.0.0
	 */
	private Vector<Action> actions;

	/**
	 * Command will only execute if the last command is match. This can be set
	 * when init the <code>Command</code> object.
	 * 
	 * @since 1.0.0
	 */
	private String checkCommandKey;

	/**
	 * Constructs an empty command with a command key.
	 * {@link jcommand.Command#checkCommandKey} will set to <code>null</code>.
	 * 
	 * @param commandKey
	 *            identify key of the command
	 * @since 1.0.0
	 */
	public Command(String commandKey) {
		this.commandKey = commandKey.toLowerCase();
		this.checkCommandKey = null;
		this.actions = new Vector<Action>(10, 5);
	}

	/**
	 * Constructs an empty command with specific.
	 * {@link jcommand.Command#commandKey} and
	 * {@link jcommand.Command#checkCommandKey}
	 * 
	 * @param commandKey
	 *            identify key of the command
	 * @param checkCommandKey
	 *            conidtion commandKey, this action will only execute if the
	 *            last command is matched
	 * @since 1.0.0
	 */
	public Command(String commandKey, String checkCommandKey) {
		this.commandKey = commandKey.toLowerCase();
		this.checkCommandKey = checkCommandKey;
		this.actions = new Vector<Action>(10, 5);
	}

	/**
	 * Appends the specified action to the end of this command.
	 * 
	 * @param action
	 *            action to be appended to this command
	 * @see jcommand.Action
	 * @since 1.0.0
	 */
	public void addAction(Action action) {
		actions.add(action);
	}

	/**
	 * Returns the command key of command.
	 * 
	 * @return the command key of command
	 * @since 1.0.0
	 */
	public String getCommandKey() {
		return commandKey;
	}

	/**
	 * Execute the command.
	 * 
	 * @throws IOException
	 * @see jcommand.Action#run()
	 * @since 1.0.0
	 */
	public void runCommand() throws IOException {
		for (int i = 0; i < actions.size(); i++)
			actions.elementAt(i).run();
	}

	/**
	 * Remove the action at the specified index.
	 * 
	 * @param index
	 *            Index of the action. The index of first action is 0.
	 * @return true if the action is removed successfully.
	 * @since 1.0.0
	 */
	public boolean removeAction(int index) {
		try {
			actions.removeElementAt(index);
			return true;
		} catch (ArrayIndexOutOfBoundsException e) {
			return false;
		}
	}

	/**
	 * Remove all the action in the command.
	 * 
	 * @since 1.0.0
	 * 
	 */
	public void removeAllActions() {
		actions.removeAllElements();
	}

	/**
	 * Returns the first action (the item at index 0) of this command.
	 * 
	 * @return the first action of this command.
	 * @since 1.0.0
	 */
	public Action firstAction() {
		return actions.firstElement();
	}

	/**
	 * Returns the last action of this command.
	 * 
	 * @return the last action of this command.
	 * @since 1.0.0
	 */
	public Action lastAction() {
		return actions.lastElement();
	}

	/**
	 * Return the action at the specified index.
	 * 
	 * @param index
	 *            Index of the action. The index of first action is 0.
	 * @return action at the specified index.
	 * @since 1.0.0
	 */
	public Action getActionAt(int index) {
		return actions.elementAt(index);
	}

	/**
	 * Return the number of actions in this command.
	 * 
	 * @return number of actions in this command
	 * @since 1.0.0
	 */
	public int size() {
		return actions.size();
	}

	/**
	 * Tests if this command has no actions.
	 * 
	 * @return <code>true</code> if and only if this command has no actions,
	 *         that is, its size is zero; <code>false</code> otherwise.
	 * @since 1.0.0
	 */
	public boolean isEmpty() {
		return actions.isEmpty();
	}

	/**
	 * Return the checking command key. If the key is set to null, the command
	 * execute without any condition checking, otherwise, before the command is
	 * execute, the key must be matched.
	 * 
	 * @return checking command key
	 * @since 1.0.0
	 */
	public String getCheckCommandKey() {
		return checkCommandKey;
	}
}
